
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>

#define BUFFER_SIZE 4096 /* <= 4096 */

/* NS: network sensitive
 * CH: cpu hunger
 */
enum TYPE {NS=0x01, HG=0x10};

FILE *fifo = NULL;
mode_t mode = 0755;
char path[] = "./test.fifo";

/* size: 56B */
struct domain_table {
    int domain_id;
    int domain_type;
    int pool_id;
    int ring_rx_of; /* if rx ring overflow */
    int ring_rx;   /* rx ring request length */
    int ring_tx;  /* tx ring request length */
    float domain_load;
    char domain_name[32];
};

/* size: 36B */
struct net_table {
    int domain_id;
    long bytes_rx;
    long bytes_tx;
    long packets_rx;
    long packets_tx;
};

static void data2json(char *buf, const struct domain_table *dt, size_t dt_size, const struct net_table *nt, size_t nt_size) {
    bzero(buf, BUFFER_SIZE);
    sprintf(&buf[strlen(buf)], "{");
    /* domain_table */
    sprintf(&buf[strlen(buf)], "\"domain_table\":[");
    int i = 0;
    for (; i < dt_size; ++ i) {
        sprintf(&buf[strlen(buf)], "{");
        sprintf(&buf[strlen(buf)], "\"domain_id\":%d,", dt->domain_id);
        sprintf(&buf[strlen(buf)], "\"domain_type\":%d,", dt->domain_type);
        sprintf(&buf[strlen(buf)], "\"pool_id\":%d,", dt->pool_id);
        sprintf(&buf[strlen(buf)], "\"ring_rx_of\":%d,", dt->ring_rx_of);
        sprintf(&buf[strlen(buf)], "\"ring_rx\":%d,", dt->ring_rx);
        sprintf(&buf[strlen(buf)], "\"ring_tx\":%d,", dt->ring_tx);
        sprintf(&buf[strlen(buf)], "\"domain_load\":%f,", dt->domain_load);
        sprintf(&buf[strlen(buf)], "\"doamin_name\":\"%s\"", dt->domain_name);
        sprintf(&buf[strlen(buf)], "}");
        sprintf(&buf[strlen(buf)], ",");
    }
    size_t len = strlen(buf);
    buf[len-1] = '\0'; /* overlap last , */
    sprintf(&buf[strlen(buf)], "],");
    /* domain_table */
    sprintf(&buf[strlen(buf)], "\"net_table\":[");
    for (i = 0; i < nt_size; ++ i) {
        sprintf(&buf[strlen(buf)], "{");
        sprintf(&buf[strlen(buf)], "\"domain_id\":%d,", nt->domain_id);
        sprintf(&buf[strlen(buf)], "\"bytes_rx\":%ld,", nt->bytes_rx);
        sprintf(&buf[strlen(buf)], "\"bytes_tx\":%ld,", nt->bytes_tx);
        sprintf(&buf[strlen(buf)], "\"packets_rx\":%ld,", nt->packets_rx);
        sprintf(&buf[strlen(buf)], "\"packets_tx\":%ld", nt->packets_tx);
        sprintf(&buf[strlen(buf)], "}");
        sprintf(&buf[strlen(buf)], ",");
    }
    len = strlen(buf);
    buf[len-1] = '\0';
    sprintf(&buf[strlen(buf)], "]}");
}

static void sigint_handler(int signo) {
    if (fifo != NULL) {
        fclose(fifo);
        fifo = NULL;
    }
    unlink(path);
}

static void exit_handler(void) {
    if (fifo != NULL) {
        fclose(fifo);
        fifo = NULL;
    }
    unlink(path);
}

int main(int argc, char *argv[]) {
    int stat_fifo = mkfifo(path, mode);
    char buffer[BUFFER_SIZE];
    struct sigaction nsa, osa;
    
    nsa.sa_handler = sigint_handler;
    sigemptyset(&nsa.sa_mask);
    nsa.sa_flags = 0;
    if (sigaction(SIGINT, &nsa, &osa) < 0)
        perror(strerror(errno));

    if (stat_fifo != 0) {
        fprintf(stderr, "fail to make fifo.\n");
        exit(EXIT_FAILURE);
    }

    atexit(exit_handler);

    fifo = fopen(path, "w");
    if (fifo == NULL) {
        fprintf(stderr, "fail to open fifo.\n");
        exit(EXIT_FAILURE);
    }

    int cycle = 0;
    while (1) {
        ++ cycle;
        struct domain_table dt[2];
        struct net_table nt[2];
        dt[0].domain_id = cycle%100;
        dt[0].domain_type = cycle%4;
        dt[0].pool_id = cycle%2;
        dt[0].ring_rx = cycle%2;
        dt[0].ring_rx = cycle%257;
        dt[0].ring_tx = cycle%257;
        dt[0].domain_load = cycle%100;
        bzero(dt[0].domain_name, 32);
        sprintf(dt[0].domain_name, "test");
        nt[0].domain_id = cycle%100;
        nt[0].bytes_rx = 20000 * (cycle%100);
        nt[0].bytes_tx = 10000 * (cycle%100);
        nt[0].packets_rx = 200 * (cycle%100);
        nt[0].packets_rx = 100 * (cycle%100);
        dt[1] = dt[0];
        nt[1] = nt[0];

        bzero(buffer, BUFFER_SIZE);
        data2json(buffer, dt, 2, nt, 2);
        int size = fwrite(buffer, sizeof (buffer), 1, fifo);
        if (size != 1) {
            fprintf(stderr, "fail to write fifo.\n");
            exit(EXIT_FAILURE);
        }
        fflush(fifo);
        sleep(1);
    }
    exit(EXIT_SUCCESS);
}
